<?php

	namespace org\tekuna\test\core\configuration;


	use \PHPUnit_Framework_TestCase;

	use org\tekuna\core\configuration\ConfigurationNode;
	use org\tekuna\core\configuration\ConfigurationException;
	use org\tekuna\core\configuration\ConfigurationElement;
	use org\tekuna\core\configuration\ConfigurationAttribute;


	class ConfigElementTest extends PHPUnit_Framework_TestCase {


		public function testAttribute() {

			$objAttribute = new ConfigurationAttribute('x', 'y', 'z');

			$this -> doTestNode($objAttribute);

			$objElement = new ConfigurationElement('foo', 'bar', 'baz');
			$objAttribute -> setElement($objElement);

			$this -> assertEquals($objElement, $objAttribute -> getElement());
			$this -> assertTrue($objElement === $objAttribute -> getElement());
		}


		public function testElement() {

			$this -> doTestNode(new ConfigurationElement('x', 'y', 'z'));
		}


		private function doTestNode(ConfigurationNode $objNode) {

			$this -> assertEquals('x', $objNode -> getAspect());
			$this -> assertEquals('y', $objNode -> getName());
			$this -> assertEquals('z', $objNode -> getValue());

			$objNode -> setAspect('testAspect');
			$objNode -> setName('testName');
			$objNode -> setValue('testValue');

			$this -> assertEquals('testAspect', $objNode -> getAspect());
			$this -> assertEquals('testName', $objNode -> getName());
			$this -> assertEquals('testValue', $objNode -> getValue());
		}


		public function testValueTypeConversions() {

			$objNode = new ConfigurationElement('aspect', 'name', '12');
			$this -> assertTrue(12 === $objNode -> getValueAsInteger());
			$this -> assertTrue(12.0 === $objNode -> getValueAsFloat());

			$objNode = new ConfigurationElement('aspect', 'name', ' 8.15');
			$this -> assertTrue(8 === $objNode -> getValueAsInteger());
			$this -> assertTrue(8.15 === $objNode -> getValueAsFloat());

			$objNode = new ConfigurationElement('aspect', 'name', 'true');
			$this -> assertTrue($objNode -> getValueAsBoolean());

			$objNode = new ConfigurationElement('aspect', 'name', "\n\tfalse  \r ");
			$this -> assertFalse($objNode -> getValueAsBoolean());
		}


		/**
		 * @expectedException org\tekuna\core\configuration\ConfigurationException
		 */
		public function testIllegalBooleanValue() {

			$objNode = new ConfigurationElement('aspect', 'name', 'definitively no boolean!');
			$objNode -> getValueAsBoolean();
		}


		public function testElementHierarchy() {

			// build test data
			$objRootElement = new ConfigurationElement('test', 'root', 'root');
			$objChildElement1 = new ConfigurationElement('test', 'type', 'child1');
			$objChildElement2 = new ConfigurationElement('test', 'class', 'child2');
			$objChildElement3 = new ConfigurationElement('live', 'class', 'child3');


			// test addChildElement
			$objRootElement -> addChildElement($objChildElement1);
			$objRootElement -> addChildElement($objChildElement2);
			$objChildElement2 -> addChildElement($objChildElement3);


			// test getParentElement
			$this -> assertEquals($objRootElement, $objChildElement1 -> getParentElement());
			$this -> assertEquals($objRootElement, $objChildElement2 -> getParentElement());
			$this -> assertEquals($objChildElement2, $objChildElement3 -> getParentElement());


			// test getChildElements, hasChildElement, removeChildElement
			$this -> assertEquals(2, count($objRootElement -> getChildElements()));
			$this -> assertEquals(array(0 => $objChildElement1, 1 => $objChildElement2), $objRootElement -> getChildElements());
			$this -> assertTrue($objRootElement -> hasChildElement('test', 'type'));

			$objRootElement -> removeChildElement($objChildElement1);
			$this -> assertEquals(1, count($objRootElement -> getChildElements()));
			$this -> assertEquals(array(1 => $objChildElement2), $objRootElement -> getChildElements());
			$this -> assertFalse($objRootElement -> hasChildElement('test', 'type'));

			$objRootElement -> addChildElement($objChildElement1);
			$this -> assertEquals(2, count($objRootElement -> getChildElements()));
			$this -> assertEquals(array(1 => $objChildElement2, 2 => $objChildElement1), $objRootElement -> getChildElements());
			$this -> assertTrue($objRootElement -> hasChildElement('test', 'type'));


			// add child element to another root
			$this -> assertFalse($objRootElement -> hasChildElement('live', 'class'));
			$this -> assertTrue($objChildElement2 -> hasChildElement('live', 'class'));
			$this -> assertEquals($objChildElement2, $objChildElement3 -> getParentElement());

			$objRootElement -> addChildElement($objChildElement3);
			$this -> assertTrue($objRootElement -> hasChildElement('live', 'class'));
			$this -> assertFalse($objChildElement2 -> hasChildElement('live', 'class'));
			$this -> assertEquals($objRootElement, $objChildElement3 -> getParentElement());

			$objChildElement2 -> addChildElement($objChildElement3);
			$this -> assertFalse($objRootElement -> hasChildElement('live', 'class'));
			$this -> assertTrue($objChildElement2 -> hasChildElement('live', 'class'));
			$this -> assertEquals($objChildElement2, $objChildElement3 -> getParentElement());


			// test getFirstChildElement
			$this -> assertEquals($objChildElement1, $objRootElement -> getFirstChildElement('test', 'type'));
			$this -> assertEquals($objChildElement2, $objRootElement -> getFirstChildElement('test', 'class'));


			// test getParentElement, setParentElement
			$this -> assertEquals($objRootElement, $objChildElement1 -> getParentElement());
			$this -> assertTrue($objRootElement -> hasChildElement('test', 'type'));
			$this -> assertFalse($objChildElement2 -> hasChildElement('test', 'type'));
			$this -> assertEquals(2, count($objRootElement -> getChildElements()));

			$objChildElement1 -> setParentElement($objChildElement2);
			$this -> assertEquals($objChildElement2, $objChildElement1 -> getParentElement());
			$this -> assertFalse($objRootElement -> hasChildElement('test', 'type'));
			$this -> assertTrue($objChildElement2 -> hasChildElement('test', 'type'));
			$this -> assertEquals(1, count($objRootElement -> getChildElements()));

			$objChildElement1 -> setParentElement($objRootElement);
			$this -> assertEquals($objRootElement, $objChildElement1 -> getParentElement());
			$this -> assertTrue($objRootElement -> hasChildElement('test', 'type'));
			$this -> assertFalse($objChildElement2 -> hasChildElement('test', 'type'));
			$this -> assertEquals(2, count($objRootElement -> getChildElements()));


			// test getAllChildElements
			$objChildElement4 = new ConfigurationElement('test', 'type', 'child4');
			$objChildElement5 = new ConfigurationElement('test', 'class', 'child5');
			$objRootElement -> addChildElement($objChildElement4);
			$objRootElement -> addChildElement($objChildElement5);

			$this -> assertEquals(array(), $objRootElement -> getAllChildElements('foo', 'bar'));
			$this -> assertEquals(array($objChildElement1, $objChildElement4), $objRootElement -> getAllChildElements('test', 'type'));
			$this -> assertEquals(array($objChildElement2, $objChildElement5), $objRootElement -> getAllChildElements('test', 'class'));
		}


		public function testAttributeHierarchy() {

			// build test data
			$objRootElement = new ConfigurationElement('test', 'root', 'root');
			$objChildElement1 = new ConfigurationElement('test', 'type', 'child1');
			$objRootElement -> addChildElement($objChildElement1);

			$objAttribute1 = new ConfigurationAttribute('test', 'name', 'attr1');
			$objAttribute2 = new ConfigurationAttribute('test', 'name2', 'attr2');


			// test hasAttribute, getAttributes, addAttribute, getElement on ConfigurationAttribute
			$this -> assertEquals(0, count($objRootElement -> getAttributes()));
			$this -> assertFalse($objRootElement -> hasAttribute('test', 'name'));
			$this -> assertEquals(array(), $objRootElement -> getAttributes());
			$this -> assertEquals(null, $objAttribute1 -> getElement());

			$objRootElement -> addAttribute($objAttribute1);
			$this -> assertEquals(1, count($objRootElement -> getAttributes()));
			$this -> assertTrue($objRootElement -> hasAttribute('test', 'name'));
			$this -> assertEquals(array(0 => $objAttribute1), $objRootElement -> getAttributes());
			$this -> assertEquals($objRootElement, $objAttribute1 -> getElement());


			// test setElement on ConfigurationAttribute
			$this -> assertEquals(null, $objAttribute2 -> getElement());

			$objAttribute2 -> setElement($objRootElement);
			$this -> assertEquals(2, count($objRootElement -> getAttributes()));
			$this -> assertEquals(array(0 => $objAttribute1, 1 => $objAttribute2), $objRootElement -> getAttributes());
			$this -> assertEquals($objRootElement, $objAttribute2 -> getElement());

			$objAttribute2 -> setElement($objChildElement1);
			$this -> assertEquals(1, count($objRootElement -> getAttributes()));
			$this -> assertEquals(array(0 => $objAttribute1), $objRootElement -> getAttributes());
			$this -> assertEquals($objChildElement1, $objAttribute2 -> getElement());


			// test removeAttribute
			$objRootElement -> removeAttribute($objAttribute1);
			$this -> assertEquals(0, count($objRootElement -> getAttributes()));
			$this -> assertEquals(array(), $objRootElement -> getAttributes());
			$this -> assertEquals(null, $objAttribute1 -> getElement());


			// test getAttribute
			$this -> assertEquals($objAttribute2, $objChildElement1 -> getAttribute('test', 'name2'));
		}
	}
